package cn.jsu.oj.dispatchServer.satellite.client;

import cn.jsu.oj.dispatchServer.satellite.factory.Factory;
import cn.jsu.oj.dispatchServer.satellite.handler.Handler;
import cn.jsu.oj.dispatchServer.satellite.pojo.net.AbsPackNet;
import cn.jsu.oj.dispatchServer.satellite.pojo.net.PackNet;
import cn.jsu.oj.dispatchServer.satellite.pojo.net.RequestNet;
import cn.jsu.oj.dispatchServer.satellite.mode.subscribe.Observer;
import cn.jsu.oj.dispatchServer.satellite.util.SpringUtil;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 中情局客户端
 *
 * @author shan
 * @date 2022/06/29
 */
@Slf4j
public abstract class AbsCiaClient implements Client, Observer {

    Factory handlerFactory;
    
    ExecutorService executorService;

    /**
     * 连接通道
     */
    private Channel channel;
    
    /**
     * 消息队列
     */
    private LinkedBlockingQueue<Object> messageQueue;
    
    /**
     * 关闭标记
     */
    private Boolean isClose;

    /**
     * 依赖注入
     */
    public AbsCiaClient() {
        this.handlerFactory = (Factory) SpringUtil.getBean("handlerFactory");
        this.executorService = (ExecutorService) SpringUtil.getBean("executorService");
    }

    /**
     * 获取连接通道
     *
     * @return {@link Channel }
     */
    public Channel getChannel() {
        return this.channel;
    }

    /**
     * 客户端初始化
     *
     * @param channel 通道
     */
    @Override
    public void init(Channel channel) {
        this.channel = channel;
        this.isClose = false;
        messageQueue = new LinkedBlockingQueue<>(1024);
    }

    /**
     * 数据包压入
     *
     * @param packNet 包网
     */
    @Override
    public void addPack(PackNet<?> packNet) {
        try {
            this.messageQueue.put(packNet);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 客户端关闭
     */
    @Override
    public void close() {
        this.isClose = true;
        this.messageQueue.clear();
        if (this.channel != null) {
            this.channel.close();
        }
    }

    /**
     * 客户端数据处理线程
     *
     */
    @Override
    public void run() {
        while (!this.isClose) {
            try {
                PackNet<?> packNet = (PackNet<?>) this.messageQueue.take();
                log.info("----------匹配成功......");
                Short typeNo = ((AbsPackNet) packNet.getMessage()).getTypeNo();
                executorService.execute(() -> {
                    try {
                        ((Handler) handlerFactory.getProduct(typeNo)).handle(packNet);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 观察者状态更新
     *
     * @param message 消息
     */
    @Override
    public void update(Object message) {
        RequestNet requestNet = (RequestNet) message;
        try {
            this.channel.writeAndFlush(requestNet.serialize());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
